package service

import (
	"fmt"
	"git.huoys.com/block_chain/mall/ecode"
	userApi "git.huoys.com/block_chain/mall/internal/user/api"
	"git.huoys.com/block_chain/mall/pkg/tool"
	"github.com/cespare/xxhash"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	"strconv"
	"time"
)

//todo 签发新token的时候 校验uid和deviceid是否存在 如果存在旧token 应删除并覆盖
func (s *userService) IssueToken(uid uint64, device string) (token string, err error) {
	resp, err := s.GetUser(uid)
	if err != nil {
		s.log.Error("CheckPassword Error", zap.Any("Uid", uid), zap.Error(err))
		return "", ecode.Unauthorized
	} else {
		tokeninfo := userApi.UserTokenInfo{
			Uid:    resp.ID,
			Device: device,
			Expire: time.Now().Add(time.Hour * 720).Unix(),
		}
		//检查该设备是否已经登录过 同设备顶号处理
		device_tk, _ := s.rpo.GetDeviceToken(tokeninfo.Uid, tokeninfo.Device)

		if device_tk != "" {
			if err := s.rpo.RemoveToken(device_tk); err != nil {
				//todo remove token失败 顶号失败的时候 错误处理
				s.log.Error("RemoveOldToken Error", zap.Any("device_tk", device_tk), zap.Error(err))
			}
		}

		token, err = genToken(tokeninfo)
		if err != nil {
			s.log.Error("genToken() error", zap.Any("userinfo", tokeninfo), zap.Error(err))
			return "", ecode.Unauthorized
		}
		err = s.rpo.SetToken(token, tokeninfo)
		if err != nil {
			s.log.Error("SetToken into redis error", zap.Any("token", token), zap.Any("tokeninfo", tokeninfo), zap.Error(err))
			return "", ecode.ServerErr
		}
		return token, nil
	}
}

func (s *userService) UpdateToken(oldtoken string) (newtoken string, err error) {
	if oldtoken == "" {
		//token为空
		return "", ecode.ErrTokenRequired
	}

	tokeninfo, err := s.rpo.GetToken(oldtoken)
	if err != nil {
		//token无效
		return "", ecode.ErrInvalidToken
	}

	if tokeninfo.Expire < time.Now().Unix() {
		//token过期
		return "", ecode.ErrInvalidToken
	} else {
		tokeninfo.Expire = time.Now().Add(time.Hour * 720).Unix()
		if err := s.rpo.RemoveToken(oldtoken); err != nil {
			s.log.Error("RemoveOldToken Error", zap.Any("oldtoken", oldtoken), zap.Error(err))
		}
		newtoken, err = genToken(tokeninfo)
		if err != nil {
			s.log.Error("genToken() error", zap.Any("userinfo", tokeninfo), zap.Error(err))
			return "", ecode.Unauthorized
		}
		err = s.rpo.SetToken(newtoken, tokeninfo)
		if err != nil {
			s.log.Error("SetToken into redis error", zap.Any("token", newtoken), zap.Any("tokeninfo", tokeninfo), zap.Error(err))
			return "", ecode.ServerErr
		}
		return newtoken, nil
	}
}

func (s *userService) VerifyToken(token string) (VerifyResult bool, Uid uint64, err error) {
	if token == "" {
		//token为空
		return false, Uid, ecode.ErrTokenRequired
	}

	tokeninfo, err := s.rpo.GetToken(token)
	if err != nil {
		//token无效
		return false, Uid, ecode.ErrInvalidToken
	}

	Uid = tokeninfo.Uid

	if tokeninfo.Expire < time.Now().Unix() {
		//token过期
		return false, Uid, ecode.ErrTokenExpired
	} else {
		return true, Uid, nil
	}
}

func genToken(userinfo userApi.UserTokenInfo) (token string, err error) {
	token = fmt.Sprintf(`%x%x`, xxhash.Sum64String(tool.RandStringBytesMaskImprSrcUnsafe(16)), xxhash.Sum64String(strconv.FormatUint(uint64(userinfo.Uid), 10)))
	if token == "" {
		return token, errors.New("userinfo err,please check userinfo")
	}
	return token, nil
}
